package com.glsc.ngateway.platform.controller;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import com.alibaba.excel.util.CollectionUtils;
import com.glsc.ngateway.common.api.common.ex.GatewayException;
import com.glsc.ngateway.common.api.common.ex.Result;
import com.glsc.ngateway.common.api.common.utils.JsonUtil;
import com.glsc.ngateway.common.api.flowable.dto.demand.FileType;
import com.glsc.ngateway.common.api.flowable.dto.demand.FlowableAppendDto;
import com.glsc.ngateway.common.api.flowable.dto.demand.ReportShowResponse;
import com.glsc.ngateway.common.api.flowable.feign.IFeignFlowableService;
import com.glsc.ngateway.common.api.flowable.resp.FlowableResponse;
import com.glsc.ngateway.common.api.flowable.resp.ResponseUploadDto;
import com.glsc.ngateway.common.api.platform.resp.PlatformResponse;
import com.glsc.ngateway.platform.service.CommonService;
import com.glsc.ngateway.platform.utils.DateUtils;
import com.glsc.ngateway.platform.utils.DocUtils;
import com.glsc.ngateway.platform.utils.FileUtil;
import com.glsc.ngateway.platform.utils.TokenUtil;
import com.google.common.collect.ImmutableList;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

@RestController
@RequestMapping(value = "/common")
public class CommonController {

    Logger logger = LoggerFactory.getLogger(this.getClass());

    @Resource
    IFeignFlowableService feignDemandService;

    @Resource
    CommonService commonService;

    @Autowired
    TokenUtil tokenUtil;

    @Value("${demand.downloadUrl}")
    String downloadUrl;

    @Value("${file.uploadPath}")
    String uploadPath;  //项目地址
    @Value("${file.downLoadUrl}")
    String downLoadUrl;   //虚拟地址


    @RequestMapping(method = RequestMethod.POST, value = "uploadDoc")
    public PlatformResponse<List<Map<String, String>>> uploadDoc(HttpServletRequest request, @RequestPart(value = "file") MultipartFile[] file) {
        PlatformResponse<List<Map<String, String>>> ret = new PlatformResponse();
        try {
            //1.调用网关系统上传文件
            FlowableResponse<ResponseUploadDto> nwret = feignDemandService.uploadDoc(file);
            if (nwret.getStatus() == 0) {
                //"annexId": "http://10.1.81.200:12580/flowable/common/oaDownloadAppendix/ee7ded5a-2198-4d56-a44d-b2af055e227d",
                //"annexName": "需求测试文档.docx"
                List<Map<String, String>> list = (List<Map<String, String>>) nwret.getData().getFileList();
                list.forEach(r -> {
                    r.put("appendixId", r.get("annexId").substring(r.get("annexId").lastIndexOf("/") + 1));
                    r.put("appendixName", r.get("annexName"));
                });

                ret = PlatformResponse.successData(list);
            } else {
                ret = PlatformResponse.failedMsg("操作失败", nwret.getMsg());
            }

        } catch (Exception e) {
            ret = PlatformResponse.failedMsg("操作失败", e.getMessage());
            logger.error("uploadDoc异常！", e);
        }

        return ret;
    }

    /**
     * 富文本控件上传
     * @param request
     * @param files
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "/uploadEditor", method = RequestMethod.POST)
    public JSONObject uploaduploadEditor(HttpServletRequest request, @RequestParam("file") MultipartFile[] files) throws Exception {
        //这里能直接得到文件数组
        List filePathList = new ArrayList<>();
        JSONObject res = new JSONObject();
        if (files == null) {
            throw new IOException("上传失败：文件为空");
        }
        for (MultipartFile file : files) {
            String appendixId = UUID.randomUUID().toString();
            //通过flowable上传附件用20220101格式
            //通过oaflow上传附件用2022-01-01格式  要注意 现在也统一改成20220101格式
            String today = DateUtils.today();
            String fileName = file.getOriginalFilename();
            String resPath = DocUtils.saveFile(file.getBytes(), uploadPath + "/", appendixId+fileName);
//            if (null == fileName || fileName.equals("")) {
//                throw PlatformException.errorWithOutMail("上传文件异常，文件名称为空");
//            }
//            if (resPath.equals(GatewayConstant.EXCEPTION)) {
//                throw new BusinessException(ExceptionConstant.IO, "上传文件异常，文件名称为：" + fileName);
//            }

            String filePath =  downLoadUrl + appendixId+fileName;

//            //服务器路径加项目名称
//            String imageUrl = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + request.getContextPath();
//            //图片真实路径
//            String fileRealPath = file.getOriginalFilename();
//            String suffix = fileRealPath.substring(fileRealPath.lastIndexOf("."));
//            String fileName = System.currentTimeMillis()+"_" +suffix;
//            //把服务器路径和图片路径拼接起来
//            String path = uploadPath;
//            File targetFile = new File(path, fileName);
//            Object filePath =  accessPath+fileName;
//            if(!targetFile.exists()){
//                try {
//                    targetFile.createNewFile();
//                } catch (IOException e) {
//                    e.printStackTrace();
//                }
//            }
//            try {
//                file.transferTo(targetFile);
//            } catch (Exception e) {
//                e.printStackTrace();
//            }
//            //成功返回示例：{"errno": 0,// data 是一个数组，返回图片的线上地址
//            //    "data": [
//            //        "图片1地址",
//            //        "图片2地址",
//            //        "……"
//            //    ]}
////            {"errno":0,"data":"/upload/markPic/1610434244822_.jpg"}
            filePathList.add(filePath);
        }
        res.put("errno",0);
        res.put("data",filePathList);
        System.out.println(res);
        return res;
    }

    @RequestMapping(method = RequestMethod.GET, value = "picDownload/{appendixId}")
    public byte[] picDownload(@PathVariable("appendixId") String appendixId, HttpServletRequest request) throws IOException {

        String targetName = uploadPath + "/" + appendixId;
        HttpHeaders headers = new HttpHeaders();
        ResponseEntity<byte[]> entity = null;
        InputStream in = null;
        in = new FileInputStream(new File(targetName));
        byte[] bytes = new byte[in.available()];
        String imageName = targetName;
        //处理IE下载文件的中文名称乱码的问题
        String header = request.getHeader("User-Agent").toUpperCase();
        if (header.contains("MSIE") || header.contains("TRIDENT") || header.contains("EDGE")) {
            imageName = URLEncoder.encode(imageName, "utf-8");
            imageName = imageName.replace("+", "%20"); //IE下载文件名空格变+号问题
        } else {
            imageName = new String(imageName.getBytes(), "iso-8859-1");
        }
        in.read(bytes);
        headers.add("Content-Disposition", "attachment;filename=" + imageName);
        return bytes;
    }

    @GetMapping("/getContentById")
    @ApiOperation(value = "根据档案Id查询档案字节流", notes = "根据档案Id查询档案字节流")
    public Object getContentById(@ApiParam(required = true, value = "档案ID") @RequestParam(value = "appendixId", required = true) String appendixId
            , HttpServletRequest request
            , HttpServletResponse response) throws IOException {
        if (null == appendixId || appendixId.length() < 0) {
            throw GatewayException.error("查询档案ID不合法");
        }

        ResponseEntity<List<FlowableAppendDto>> appendInfos = feignDemandService.getAppendixInfos(ImmutableList.of(appendixId));
        List<FlowableAppendDto> documentInfoList = appendInfos.getBody();
        if (CollectionUtils.isEmpty(documentInfoList)) {
            return Result.fail("档案不存在或文件名为空");
        }
        String fileName = documentInfoList.get(0).getAppendixName();
        if (fileName.endsWith(".jpg") || fileName.endsWith(".jpeg") || fileName.endsWith(".png")) {
            response.setContentType("image/png");
        } else {
            fileName = java.net.URLEncoder.encode(fileName, "UTF-8");
            //            String userAgent = request.getHeader("User-Agent");
            //
            //            // 针对IE或者以IE为内核的浏览器：
            //            if (userAgent.contains("MSIE") || userAgent.contains("Trident")) {
            //                fileName = java.net.URLEncoder.encode(fileName, "UTF-8");
            //            } else {
            //                // 非IE浏览器的处理：
            //                fileName = java.net.URLEncoder.encode(fileName, "UTF-8"); //new String(fileName.getBytes("UTF-8"), "UTF-8");
            //            }
            response.setContentType("application/octet-stream");
            response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
            response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
        }
        OutputStream output = response.getOutputStream();
        byte[] bytes = FileUtil.readByteFromFilePath(documentInfoList.get(0).getAppendixPath());
        if (null == bytes) {
            output.close();
            return null;
        }
        ByteArrayInputStream in = new ByteArrayInputStream(bytes);
        int len;
        byte[] buf = new byte[1024];
        while ((len = in.read(buf)) != -1) {
            output.write(buf, 0, len);
        }
        output.flush();
        output.close();
        return null;
    }


    @RequestMapping(method = RequestMethod.GET, value = "downloadDoc")
    @Deprecated
    public PlatformResponse<byte[]> downloadDoc(@RequestParam(value = "appendixId", required = true) String appendixId) {
        PlatformResponse<byte[]> ret = null;

        try {
            ResponseEntity<byte[]> nwret = feignDemandService.downloadDemandAppendix(appendixId);
            if (nwret != null) {
                ret = PlatformResponse.successData(nwret.getBody());
            } else {
                ret = PlatformResponse.failedMsg("文件下载失败");
            }

        } catch (Exception e) {
            ret = PlatformResponse.failedMsg("操作失败", e.getMessage());
            logger.error("downloadDoc异常！", e);
        }

        return ret;
    }

    @RequestMapping(method = RequestMethod.GET, value = "showDoc")
    public PlatformResponse<ReportShowResponse> show(@RequestParam(value = "appendixId", required = true) String appendixId,
                                                     @RequestParam(value = "appendixName", required = true) String appendixName) {
        PlatformResponse<ReportShowResponse> ret = null;
        try {
            String title = appendixName;
            String url = downloadUrl + appendixId;
            String token = tokenUtil.generateToken(JsonUtil.Obj2Str(new ReportShowResponse(title, url, FileType.valueOf(appendixName.substring(appendixName.lastIndexOf(".") + 1)))));

            ReportShowResponse resdata = new ReportShowResponse(title, url, token, FileType.valueOf(appendixName.substring(appendixName.lastIndexOf(".") + 1)));
            ret = PlatformResponse.successData(resdata);
            ret.setFileId(title);
        } catch (Exception e) {
            ret = PlatformResponse.failedMsg("操作失败", e.getMessage());
        }

        return ret;
    }

    @GetMapping("/getContentZipByDocIds")
    @ApiOperation(value = "根据档案Ids批量下载zip文件", notes = "根据档案Ids批量下载zip文件")
    public Object getContentZipByDocIds(@ApiParam(required = true, value = "档案IDs") @RequestParam String docIds, @ApiParam(value = "zip文件名") @RequestParam(required = false) String zipFileName
            , HttpServletRequest request
            , HttpServletResponse response) throws IOException {
        if (StrUtil.isEmpty(docIds)) {
            throw GatewayException.error("查询档案IDs不合法");
        }
        String[] docIdArr = docIds.split(",");
        List<String> docIdList = new ArrayList<>();
        for (String docIdStr : docIdArr) {
            docIdList.add(docIdStr);
        }
        logger.info("根据档案Ids批量下载zip文件,docIdList:" + docIdList);
        ResponseEntity<List<FlowableAppendDto>> appendInfos = feignDemandService.getAppendixInfos(docIdList);
        List<FlowableAppendDto> documentInfoList = appendInfos.getBody();

        if (CollectionUtils.isEmpty(documentInfoList)) {
            return Result.fail("档案列表不存在或文件名为空");
        }

        //设置压缩包的名字
        //解决不同浏览器压缩包名字含有中文时乱码的问题
        if (StrUtil.isEmpty(zipFileName)) {
            zipFileName = "事件报告附件合集.zip";
        }
        if (!zipFileName.endsWith(".zip")) {
            zipFileName = zipFileName + ".zip";
        }
        String userAgent = request.getHeader("User-Agent");
        // 针对IE或者以IE为内核的浏览器：
        if (userAgent.contains("MSIE") || userAgent.contains("Trident")) {
            zipFileName = java.net.URLEncoder.encode(zipFileName, "UTF-8");
        } else {
            // 非IE浏览器的处理：
            zipFileName = new String(zipFileName.getBytes("UTF-8"), "ISO-8859-1");
        }
        response.setContentType("APPLICATION/OCTET-STREAM");
        response.setHeader("Content-Disposition", "attachment;filename=" + zipFileName);
        //设置压缩流：直接写入response，实现边压缩边下载
        ZipOutputStream zipos = null;
        try {
            zipos = new ZipOutputStream(new BufferedOutputStream(response.getOutputStream()));
            zipos.setMethod(ZipOutputStream.DEFLATED);//设置压缩方法
        } catch (Exception e) {
            logger.error("异常", e);
        }
        DataOutputStream os = null;
        //处理重名文件
        Map<String, Long> fileNameMap = documentInfoList.parallelStream().collect(Collectors.groupingBy(FlowableAppendDto::getAppendixName, Collectors.counting()));
        //循环将文件写入压缩流
        for (int i = 0; i < documentInfoList.size(); i++) {
            String filePath = documentInfoList.get(i).getAppendixPath();
            String fileName = documentInfoList.get(i).getAppendixName();
            File file = new File(filePath);//要下载文件的路径
            try {
                //添加ZipEntry，并ZipEntry中写入文件流
                //处理同名文件
                if (fileNameMap.get(fileName) > 1) {
                    fileName = commonService.reNameFileName(fileName, documentInfoList, i);
                }
                zipos.putNextEntry(new ZipEntry(fileName));
                os = new DataOutputStream(zipos);
                InputStream is = new FileInputStream(file);
                byte[] b = new byte[100];
                int length = 0;
                while ((length = is.read(b)) != -1) {
                    os.write(b, 0, length);
                }
                is.close();
                zipos.closeEntry();
            } catch (Exception e) {
                logger.error("根据档案Ids批量下载zip文件异常:", e);
            }
        }
        //关闭流
        try {
            os.flush();
            os.close();
            zipos.close();
        } catch (IOException e) {
            logger.error("根据档案Ids批量下载zip文件关闭流异常:", e);
            return null;
        }
        return null;
    }



}
